package acewem.utilities.optimisation;

import gamlss.algorithm.Gamlss;
import gamlss.distributions.DistributionSettings;
import gamlss.distributions.NO;
import gamlss.utilities.oi.CSVFileReader;

import java.util.*;

import org.apache.commons.math3.analysis.MultivariateFunction;
import org.apache.commons.math3.linear.ArrayRealVector;
import org.apache.commons.math3.linear.BlockRealMatrix;
import org.apache.commons.math3.linear.MatrixUtils;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.optimization.ConvergenceChecker;
import org.apache.commons.math3.optimization.GoalType;
import org.apache.commons.math3.optimization.MultivariateMultiStartOptimizer;
import org.apache.commons.math3.optimization.PointValuePair;
import org.apache.commons.math3.optimization.SimpleValueChecker;
import org.apache.commons.math3.optimization.direct.BOBYQAOptimizer;
import org.apache.commons.math3.optimization.direct.CMAESOptimizer;
import org.apache.commons.math3.optimization.direct.MultiDirectionalSimplex;
import org.apache.commons.math3.optimization.direct.NelderMeadSimplex;
import org.apache.commons.math3.optimization.direct.PowellOptimizer;
import org.apache.commons.math3.optimization.direct.SimplexOptimizer;
import org.apache.commons.math3.random.AbstractRandomGenerator;
import org.apache.commons.math3.random.BitsStreamGenerator;
import org.apache.commons.math3.random.CorrelatedRandomVectorGenerator;
import org.apache.commons.math3.random.GaussianRandomGenerator;
import org.apache.commons.math3.random.JDKRandomGenerator;
import org.apache.commons.math3.random.MersenneTwister;
import org.apache.commons.math3.random.NormalizedRandomGenerator;
import org.apache.commons.math3.random.RandomGenerator;
import org.apache.commons.math3.random.RandomVectorGenerator;

import acewem.market.ACEWEMmodel;


public class StochasticOptimisation {
	
	public StochasticOptimisation(){
		
	}

	
	public PointValuePair submitReportedOfferStochasticOptimisation(int idNum,  ACEWEMmodel market, Hashtable<String,Double> trueSupplyOffer){
		
		
		 String fileName = "c:\\test.csv";	
		 CSVFileReader readData = new CSVFileReader(fileName);
		 readData.readFile();
		 ArrayList<String> data = readData.storeValues;
		 
		 
		 ArrayRealVector y = new ArrayRealVector(data.size());
		 BlockRealMatrix muX = new BlockRealMatrix(data.size(), 2);
		 BlockRealMatrix sigmaX = new BlockRealMatrix(data.size(), 2);
		 BlockRealMatrix nuX = new BlockRealMatrix(data.size(), 2);
		 BlockRealMatrix tauX = new BlockRealMatrix(data.size(), 2); 
		
//double[][] X = new double[data.size()][2];

		 for(int i=0;i<data.size();i++)
		 {
			String[] line = data.get(i).split(",");
			y.setEntry(i,  Double.parseDouble(line[idNum-1]));
	
			//muX.setEntry(i, 0, Double.parseDouble(line[idNum-1+market.genCoList.size()]));
			//sigmaX.setEntry(i, 0, Double.parseDouble(line[idNum-1+2*market.genCoList.size()]));
			//nuX.setEntry(i, 0, Double.parseDouble(line[4]));
			//tauX.setEntry(i, 0, Double.parseDouble(line[4]));
			
//X[i][0] = Double.parseDouble(line[idNum-1+market.genCoList.size()]);
//X[i][1] = Double.parseDouble(line[idNum-1+2*market.genCoList.size()]);
			
			muX.setEntry(i, 0, Double.parseDouble(line[idNum-1+market.genCoList.size()]));
			muX.setEntry(i, 1, Double.parseDouble(line[idNum-1+2*market.genCoList.size()]));
			sigmaX.setEntry(i, 0, Double.parseDouble(line[idNum-1+market.genCoList.size()]));
			sigmaX.setEntry(i, 1, Double.parseDouble(line[idNum-1+2*market.genCoList.size()]));
			nuX.setEntry(i, 0, Double.parseDouble(line[idNum-1+market.genCoList.size()]));
			nuX.setEntry(i, 1, Double.parseDouble(line[idNum-1+2*market.genCoList.size()]));
			tauX.setEntry(i, 0, Double.parseDouble(line[idNum-1+market.genCoList.size()]));
			tauX.setEntry(i, 1, Double.parseDouble(line[idNum-1+2*market.genCoList.size()]));
		 }	

		 HashMap<Integer, BlockRealMatrix> designMatrices = new HashMap<Integer, BlockRealMatrix>();
		 designMatrices.put(DistributionSettings.MU, muX);
		 designMatrices.put(DistributionSettings.SIGMA, sigmaX);
		 designMatrices.put(DistributionSettings.NU, nuX);
		 designMatrices.put(DistributionSettings.TAU, tauX);
		 
		 HashMap<Integer, BlockRealMatrix> smoothMatrices = new HashMap<Integer, BlockRealMatrix>();
		 smoothMatrices.put(DistributionSettings.MU, null);
		 smoothMatrices.put(DistributionSettings.SIGMA, null);
		 smoothMatrices.put(DistributionSettings.NU, null);
		 smoothMatrices.put(DistributionSettings.TAU, null);
		 
		 Gamlss gamlss = new Gamlss(y, designMatrices, smoothMatrices, DistributionSettings.SST);
		 
		 ObjFunction function = new ObjFunction(gamlss, trueSupplyOffer);
	 
		 //choice 2
		 //PowellOptimizer optimizer = new PowellOptimizer(1e-10, Double.MIN_VALUE);
		 //PointValuePair pair = optimizer.optimize(10000, function, GoalType.MAXIMIZE, new double[]{trueSupplyOffer.get("aT"), trueSupplyOffer.get("bT")});
		 
		 //choice 3
		 //SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, Double.MIN_VALUE);
		 //optimizer.setSimplex(new NelderMeadSimplex(new double[] {1,1}));
		 //PointValuePair pair = optimizer.optimize(10000, function, GoalType.MAXIMIZE, new double[]{trueSupplyOffer.get("aT"),trueSupplyOffer.get("bT")});

	         
		 //choice 4
		 //SimplexOptimizer optimizer = new SimplexOptimizer(1e-10, Double.MIN_VALUE);
		 //optimizer.setSimplex(new MultiDirectionalSimplex(new double[] {0.5, 0.5}));
		 //PointValuePair pair = optimizer.optimize(10000, function, GoalType.MAXIMIZE, new double[] {trueSupplyOffer.get("aT"), trueSupplyOffer.get("bT")});
	         
	 		
		 //choice 5
		 BOBYQAOptimizer optimizer = new BOBYQAOptimizer(5);
		 PointValuePair pair = optimizer.optimize(10000, function, GoalType.MAXIMIZE, new double[] {trueSupplyOffer.get("aT"),
				 trueSupplyOffer.get("bT")},new double[] {trueSupplyOffer.get("aT"),trueSupplyOffer.get("bT")},new double[]
						 {trueSupplyOffer.get("aT")*1000,trueSupplyOffer.get("bT")*1000});	
		 
		 return pair;
	}
	
}		

class ObjFunction implements MultivariateFunction{
	
	Hashtable<String, Double> trueSupplyOffer;
	Gamlss gamlss;
	
	 public ObjFunction(Gamlss gamlss,  Hashtable<String, Double> trueSupplyOffer){
		
		 this.trueSupplyOffer = trueSupplyOffer;		
		 this.gamlss = gamlss;

	}		
	public double value(double[] point) {
		
	double marginalCost=(point[0]+point[1]*trueSupplyOffer.get("capTU"));
		
	Hashtable<Integer, Double> distributionParametersData = new Hashtable<Integer, Double>();
	double temp = 0;
	for (int i=0; i< gamlss.getDistr().getNumberOfDistribtionParameters(); i++)
	{
		temp = gamlss.getBeta().get(i+1).getEntry(0)  + gamlss.getBeta().get(i+1).getEntry(1)*point[0]
                +gamlss.getBeta().get(i+1).getEntry(2)*point[1];
		distributionParametersData.put(i+1, temp);
		
		if(temp <=0)
		{
			return 0.0;
		}
		
	}
//System.out.println((count++)+"___"+distributionParametersData.get(1)+"___"+point[0]+"___"+point[1]+"___ "+gamlss.getBeta().get(1).getEntry(0)+"___ "+gamlss.getBeta().get(1).getEntry(1)+"___"+gamlss.getBeta().get(1).getEntry(2));
		double p = gamlss.getDistr().p(marginalCost, distributionParametersData, false, false);
//System.out.println((marginalCost - (trueSupplyOffer.get("aT")+trueSupplyOffer.get("bT")*trueSupplyOffer.get("capTU")))*p);
		return (marginalCost - (trueSupplyOffer.get("aT")+trueSupplyOffer.get("bT")*trueSupplyOffer.get("capTU")))*p;
		
	}
}
